package bod.engine.map;

import java.awt.image.BufferedImage;

import bod.Images;
import bod.Progress;
import bod.engine.map.blocks.Back;
import bod.engine.map.blocks.Block;
import bod.engine.map.blocks.BlockType;

public class Map {

	public static final Back		sky;
	public static final Back		tunnel;
	public static final BlockType	air;
	public static final BlockType	earth;
	public static final BlockType	grass;
	public static final BlockType	sand;
	public static final BlockType	stone;
	public static final BlockType	water;

	static {
		sky = new Back(Images.skyb[0]);
		tunnel = new Back(Images.tnnl[0]);
		air = new BlockType((byte) 0, (byte) 0, Images.aire, false, false, sky);
		earth = new BlockType((byte) 100, (byte) 20, Images.erth, true, false,
				tunnel);
		grass = new BlockType((byte) 100, (byte) 20, Images.gras, true, false,
				sky);
		sand = new BlockType((byte) 100, (byte) 10, Images.sand, true, false,
				tunnel);
		stone = new BlockType((byte) 100, (byte) 80, Images.stne, true, false,
				tunnel);
		water = new BlockType((byte) 80, (byte) 40, Images.watr, false, true,
				tunnel);
	}

	public static Block getBlockByColor(int color, int x, int y) {
		switch (color) {
			case 0xFF995500:
				return new Block(earth, x, y);
			case 0xFF00FF00:
				return new Block(grass, x, y);
			case 0xFFFFFF00:
				return new Block(sand, x, y);
			case 0xFF555555:
				return new Block(stone, x, y);
			case 0xFF552200:
				return new Block(air, tunnel, x, y);
			case 0xFF0000FF:
				return new Block(water, x, y);
			default:
				return new Block(air, x, y);
		}
	}

	private int				xBlocks;
	private int				yBlocks;
	private Block[][]		blocks;
	private BufferedImage	image;

	public Map() {
		final BufferedImage map = Images.act1;
		this.xBlocks = map.getWidth();
		this.yBlocks = map.getHeight();
		this.blocks = new Block[this.xBlocks][this.yBlocks];
		this.image = new BufferedImage(this.xBlocks * Block.size, this.yBlocks
				* Block.size, BufferedImage.TYPE_INT_ARGB);
		Progress.addJob("Creating map", this.xBlocks * this.yBlocks,
				new Runnable() {

					@Override
					public void run() {
						for (int i = 0; i < xBlocks; i++) {
							for (int j = 0; j < yBlocks; j++) {
								blocks[i][j] = getBlockByColor(
										map.getRGB(i, j), i * Block.size, j
												* Block.size);
								Progress.done(1);
							}
						}
					}

				});
	}

	public void tick() {
		for (int x = 0; x < this.xBlocks; x++) {
			for (int y = 0; y < this.yBlocks; y++) {
				Block bt = y - 1 < 0 ? null : this.blocks[x][y - 1];
				Block bl = x - 1 < 0 ? null : this.blocks[x - 1][y];
				Block bb = y + 2 > this.yBlocks ? null : this.blocks[x][y + 1];
				Block br = x + 2 > this.xBlocks ? null : this.blocks[x + 1][y];
				byte dt = bt == null ? 0 : bt.getDensity();
				byte dl = bl == null ? 0 : bl.getDensity();
				byte db = bb == null ? 0 : bb.getDensity();
				byte dr = br == null ? 0 : br.getDensity();
				if (this.blocks[x][y] != null) {
					this.blocks[x][y].update(dt, dl, db, dr);
					this.blocks[x][y].tick();
				}
			}
		}
	}

	public int getWidth() {
		return this.xBlocks * Block.size;
	}

	public int getHeight() {
		return this.yBlocks * Block.size;
	}

	public Block getBlock(int x, int y) {
		if (x >= 0 && x < this.xBlocks * Block.size && y >= 0
				&& y < this.yBlocks * Block.size) {
			return this.blocks[x / Block.size][y / Block.size];
		} else {
			return null;
		}
	}

	public void setBlock(Block block, int x, int y) {
		this.blocks[x / Block.size][y / Block.size] = block;
	}

	public Block[][] getBlocks() {
		return this.blocks;
	}

	public BufferedImage getImage() {
		return this.image;
	}

}